/* This file describes gRPC protocol supported in ClickHouse.
 *
 * To use this protocol a client should send one or more messages of the QueryInfo type
 * and then receive one or more messages of the Result type.
 * According to that the service provides four methods for that:
 * ExecuteQuery(QueryInfo) returns (Result)
 * ExecuteQueryWithStreamInput(stream QueryInfo) returns (Result)
 * ExecuteQueryWithStreamOutput(QueryInfo) returns (stream Result)
 * ExecuteQueryWithStreamIO(stream QueryInfo) returns (stream Result)
 * It's up to the client to choose which method to use.
 * For example, ExecuteQueryWithStreamInput() allows the client to add data multiple times
 * while executing a query, which is suitable for inserting many rows.
 */

syntax = "proto3";

package clickhouse.grpc;

message NameAndType {
   string name = 1;
   string type = 2;
}

// Describes an external table - a table which will exists only while a query is executing.
message ExternalTable {
   // Name of the table. If omitted, "_data" is used.
   string name = 1;

   // Columns of the table. Types are required, names can be omitted. If the names are omitted, "_1", "_2", ... is used.
   repeated NameAndType columns = 2;

   // Data to insert to the external table.
   // If a method with streaming input (i.e. ExecuteQueryWithStreamInput() or ExecuteQueryWithStreamIO()) is used,
   // then data for insertion to the same external table can be split between multiple QueryInfos.
   bytes data = 3;

   // Format of the data to insert to the external table.
   string format = 4;

   // Compression type used to compress `data`.
   // Supported values: none, gzip(gz), deflate, brotli(br), lzma(xz), zstd(zst), lz4, bz2.
   string compression_type = 6;

   // Settings for executing that insertion, applied after QueryInfo.settings.
   map<string, string> settings = 5;
}

message ObsoleteTransportCompression {
   enum CompressionAlgorithm {
      NO_COMPRESSION = 0;
      DEFLATE = 1;
      GZIP = 2;
      STREAM_GZIP = 3;
   }
   enum CompressionLevel {
      COMPRESSION_NONE = 0;
      COMPRESSION_LOW = 1;
      COMPRESSION_MEDIUM = 2;
      COMPRESSION_HIGH = 3;
   }
   CompressionAlgorithm algorithm = 1;
   CompressionLevel level = 2;
}

// Information about a query which a client sends to a ClickHouse server.
// The first QueryInfo can set any of the following fields. Extra QueryInfos only add extra data.
// In extra QueryInfos only `input_data`, `external_tables`, `next_query_info` and `cancel` fields can be set.
message QueryInfo {
   string query = 1;
   string query_id = 2;
   map<string, string> settings = 3;

   // Default database.
   string database = 4;

   // Input data, used both as data for INSERT query and as data for the input() function.
   bytes input_data = 5;

   // Delimiter for input_data, inserted between input_data from adjacent QueryInfos.
   bytes input_data_delimiter = 6;

   // Default output format. If not specified, 'TabSeparated' is used.
   string output_format = 7;

   // Set it if you want the names and the types of output columns to be sent to the client.
   bool send_output_columns = 24;

   repeated ExternalTable external_tables = 8;

   string user_name = 9;
   string password = 10;
   string quota = 11;

   // Works exactly like sessions in the HTTP protocol.
   string session_id = 12;
   bool session_check = 13;
   uint32 session_timeout = 14;

   // Set `cancel` to true to stop executing the query.
   bool cancel = 15;

   // If true there will be at least one more QueryInfo in the input stream.
   // `next_query_info` is allowed to be set only if a method with streaming input (i.e. ExecuteQueryWithStreamInput() or ExecuteQueryWithStreamIO()) is used.
   bool next_query_info = 16;

   // Compression type for `input_data`.
   // Supported compression types: none, gzip(gz), deflate, brotli(br), lzma(xz), zstd(zst), lz4, bz2.
   // The client is responsible to compress data before putting it into `input_data`.
   string input_compression_type = 20;

   // Compression type for `output_data`, `totals` and `extremes`.
   // Supported compression types: none, gzip(gz), deflate, brotli(br), lzma(xz), zstd(zst), lz4, bz2.
   // The client receives compressed data and should decompress it by itself.
   // Consider also setting `output_compression_level`.
   string output_compression_type = 21;

   // Compression level.
   // WARNING: If it's not specified the compression level is set to zero by default which might be not the best choice for some compression types (see below).
   // The compression level should be in the following range (the higher the number, the better the compression):
   // none: compression level isn't used
   // gzip: 0..9; 0 means no compression, 6 is recommended by default (compression level -1 also means 6)
   // brotli: 0..11
   // lzma: 0..9; 6 is recommended by default
   // zstd: 1..22; 3 is recommended by default (compression level 0 also means 3)
   // lz4: 0..16; values < 0 mean fast acceleration
   // bz2: 1..9
   int32 output_compression_level = 19;

   // Transport compression is an alternative way to make the server to compress its response.
   // This kind of compression implies that instead of compressing just `output` the server will compress whole packed messages of the `Result` type,
   // and then gRPC implementation on client side will decompress those messages so client code won't be bothered with decompression.
   // Here is a big difference between the transport compression and the compression enabled by setting `output_compression_type` because
   // in case of the transport compression the client code receives already decompressed data in `output`.
   // If the transport compression is not set here it can still be enabled by the server configuration.
   // Supported compression types: none, deflate, gzip, stream_gzip
   // Supported compression levels: 0..3
   // WARNING: Don't set `transport_compression` and `output_compression` at the same time because it will make the server to compress its output twice!
   string transport_compression_type = 22;
   int32 transport_compression_level = 23;

   /// Obsolete fields, should not be used in new code.
   ObsoleteTransportCompression obsolete_result_compression = 17;
   string obsolete_compression_type = 18;
}

enum LogsLevel {
   LOG_NONE = 0;
   LOG_FATAL = 1;
   LOG_CRITICAL = 2;
   LOG_ERROR = 3;
   LOG_WARNING = 4;
   LOG_NOTICE = 5;
   LOG_INFORMATION = 6;
   LOG_DEBUG = 7;
   LOG_TRACE = 8;
}

message LogEntry {
   uint32 time = 1;
   uint32 time_microseconds = 2;
   uint64 thread_id = 3;
   string query_id = 4;
   LogsLevel level = 5;
   string source = 6;
   string text = 7;
}

message Progress {
   uint64 read_rows = 1;
   uint64 read_bytes = 2;
   uint64 total_rows_to_read = 3;
   uint64 written_rows = 4;
   uint64 written_bytes = 5;
}

message Stats {
   uint64 rows = 1;
   uint64 blocks = 2;
   uint64 allocated_bytes = 3;
   bool applied_limit = 4;
   uint64 rows_before_limit = 5;
}

message Exception {
   int32 code = 1;
   string name = 2;
   string display_text = 3;
   string stack_trace = 4;
}

// Result of execution of a query which is sent back by the ClickHouse server to the client.
message Result {
   string query_id = 9;
   string time_zone = 10;
   
   // The format in which `output`, `totals` and `extremes` are written.
   // It's either the same as `output_format` specified in `QueryInfo` or the format specified in the query itself.
   string output_format = 11;

   // The names and types of columns of the result written in `output`.
   repeated NameAndType output_columns = 12;

   // Output of the query, represented in the `output_format`.
   bytes output = 1;
   bytes totals = 2;
   bytes extremes = 3;

   repeated LogEntry logs = 4;
   Progress progress = 5;
   Stats stats = 6;

   // Set by the ClickHouse server if there was an exception thrown while executing.
   Exception exception = 7;

   // Set by the ClickHouse server if executing was cancelled by the `cancel` field in QueryInfo.
   bool cancelled = 8;
}

service ClickHouse {
   rpc ExecuteQuery(QueryInfo) returns (Result) {}
   rpc ExecuteQueryWithStreamInput(stream QueryInfo) returns (Result) {}
   rpc ExecuteQueryWithStreamOutput(QueryInfo) returns (stream Result) {}
   rpc ExecuteQueryWithStreamIO(stream QueryInfo) returns (stream Result) {}
}
